#include "eval_proc.h"
#include <math.h>

//-----------------------
//   Operasi Aritmatik
//-----------------------

string PLUS ( string a, string b )
/* menghasilkan a+b jika a dan b adalah integer atau real,
jika tidak mengembalikan string 'error' 
catatan : a/b mungkin minus */
{
	int Sumint;
	double Sum;
	string s;
	
	Sum = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if ((IsStringInteger(a)) && (IsStringInteger(b)))
		{
			Sumint = StringToInt(a) + StringToInt(b);
			s = IntToString(Sumint);
		}
		else
		{
			Sum = StringToDouble(a) + StringToDouble(b);
			s = DoubleToString(Sum);
		}
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string MIN ( string a, string b )
/* menghasilkan a-b jika a dan b adalah integer atau real, 
jika tidak mengembalikan string 'error' 
catatan : a/b mungkin minus */
{
	int Minusint;
	double Minus;
	string s;
	
	Minus = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if ((IsStringInteger(a)) && (IsStringInteger(b)))
		{
			Minusint = StringToInt(a) - StringToInt(b);
			s = IntToString(Minusint);
		}
		else
		{
			Minus = StringToDouble(a) - StringToDouble(b);
			s = DoubleToString(Minus);
		}
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string DIVIDE ( string a, string b )
/* menghasilkan a/b jika a dan b adalah integer atau real, 
jika tidak mengembalikan string 'error'
catatan : a/b mungkin minus 
catatan : mungkin ada pembagian dengan 0  */
{
	int Divint;
	double Div;
	string s;
	
	Div = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if(StringToDouble(b)!=0) {
			Div = StringToDouble(a) / StringToDouble(b);
			s = DoubleToString(Div);
		} else {
		s=CharToString("ERROR");
		}
		
	}
	else
	{
		s=CharToString("ERROR");
	}
	return(s);
}

string MULTI ( string a, string b )
/* menghasilkan a*b jika a dan b adalah integer atau real,
jika tidak mengembalikan string 'error' 
catatan : a/b mungkin minus */
{
	int Kaliint;
	double Kali;
	string s;
	
	Kali = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if ((IsStringInteger(a)) && (IsStringInteger(b)))
		{
			Kaliint = StringToInt(a) * StringToInt(b);
			s = IntToString(Kaliint);
		}
		else
		{
			Kali = StringToDouble(a) * StringToDouble(b);
			s = DoubleToString(Kali);
		}
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string POW ( string a, string b )
/* menghasilkan a^b jika a dan b adalah integer atau real, 
jika tidak mengembalikan string 'error'
catatan gunakan fungsi pwr di math.h, b mungkin bilangan real 
catatan : a/b mungkin minus */
{
	int Kaliint;
	double Kali;
	string s;
	
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if ((IsStringInteger(a)) && (IsStringInteger(b)))
		{
			Kaliint = pow(StringToInt(a),StringToInt(b));
			s = IntToString(Kaliint);
			
		}
		else
		{
			Kali = pow(StringToDouble(a),StringToDouble(b));
			s = DoubleToString(Kali);
			
		}
	}
	else
	{
		s=CharToString("ERROR");
	}
	if ((IsStringEqSpec(s,CharToString("-nan"))==1)||
		(IsStringEqSpec(s,CharToString("-1.#IND00"))==1))
			{s=CharToString("ERROR");}
			
	return(s);
}

string DIV ( string a, string b)
/* menghasilkan hasil operasi a div b jika a dan b adalah integer positif
 jika tidak mengembalikan string 'error' 
catatan : mungkin ada pembagian dengan 0  */
{
	int Div;
	string s;
	
	Div = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		if (IsStringInteger(a))
		{
			Div = Div + StringToInt(a);
		}
		else
		{
			Div = Div + StringToDouble(a);
		}
		
		if (IsStringInteger(b))
		{
			Div = Div / StringToInt(b);
		}
		else
		{
			Div = Div / StringToDouble(b);
		}
		s = IntToString(Div);
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string MOD ( string a, string b)
/* menghasilkan hasil operasi a mod b jika a dan b adalah integer positif
 jika tidak mengembalikan string 'error' */
{
	double Mod;
	string s;
	int Modint;
	double Div;
	
	Mod = 0;
	if (((IsStringInteger(a)) || (IsStringDouble(a))) && ((IsStringInteger(b)) || (IsStringDouble(b))))
	{
		Div = StringToInt(DIV(a,b));
		if ((IsStringInteger(a)) && (IsStringInteger(b)))
		{
			Modint = StringToInt(a) - (Div * StringToInt(b));
			s = IntToString(Modint);
		}
		else
		{
			Mod = StringToDouble(a) - (Div * StringToDouble(b));
			s = DoubleToString(Mod);
		}
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}
 
string SQR ( string a )
/* menghasilkan kuadrat dari a .jika a adalah integer atau real,
jika tidak mengembalikan string 'error'
catatan : a/b mungkin minus  */
{
	double Sqr;
	string s;
	
	Sqr = 0;
	if ((IsStringInteger(a)) || (IsStringDouble(a)))
	{
		if (IsStringInteger(a))
		{
			Sqr = pow(StringToInt(a),2);
		}
		else
		{
			Sqr = pow(StringToDouble(a),2);
		}
		s = DoubleToString(Sqr);
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string SQRT ( string a )
/* menghasilkan akar dari a. jika a adalah integer atau real,
jika tidak mengembalikan string 'error' 
catatan : a mungkin minus */
{
	double Sqr;
	string s;
	
	Sqr = 0;
	if ((IsStringInteger(a)) || (IsStringDouble(a)))
	{
		if (IsStringInteger(a))
		{
			Sqr = sqrt(StringToInt(a));
		}
		else
		{
			Sqr = sqrt(StringToDouble(a));
		}
		s = DoubleToString(Sqr);
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string MINUS ( string a )
/* menghasilkan negatif a. jika a adalah integer atau real,
jika tidak mengembalikan string 'error' 
catatan : a mungkin minus */
{
	double Sqr;
	string s;
	
	Sqr = 0;
	if ((IsStringInteger(a)) || (IsStringDouble(a)))
	{
		if (IsStringInteger(a))
		{
			Sqr = -1 * StringToInt(a);
		}
		else
		{
			Sqr = -1 * StringToDouble(a);
		}
		s = DoubleToString(Sqr);
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}


//-----------------------
//   Operasi Relasional
//-----------------------

string EQ ( string a, string b )
/* mengecek kesamaan a dan b , a dan b bisa berupa string, integer dan real
catatan : pengecekan untuk real menggunakan epsilon 
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error' */
{
	string s;
	double eps;
	
	if ((IsStringInteger(a)) && (IsStringInteger(b)))
	{
		if (StringToInt(a) == StringToInt(b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else if ((IsStringDouble(a)) && (IsStringDouble(b)))
	{
		eps = 0.000000005 * StringToDouble(a);
		if ((StringToDouble(b) >= StringToDouble(a) - eps) && (StringToDouble(b) <= StringToDouble(a) + eps))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else
	{
		if (IsStringEq(a,b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	return(s);
}

string NEQ ( string a, string b )
/* mengecek ketidaksamaan a dan b [jika a!= b return 1]
, a dan b bisa berupa string, integer dan real
catatan : pengecekan untuk real menggunakan epsilon 
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error'
catatan : ah pake fungsi diatas aja yak */
{
	boolean NN;
	
	NN = !StringToBool(EQ(a,b));
	
	return(BoolToString(NN));
}

string GT ( string a, string b )
/* mengecek apakah a lebih besar dari b, a dan b bisa berupa string, integer dan real 
catatan : pembandingan string dilakukan dengan alfabetis
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error'  */
{
	string s;
	double eps;
	
	if ((IsStringInteger(a)) && (IsStringInteger(b)))
	{
		if (StringToInt(a) > StringToInt(b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else if ((IsStringDouble(a)) && (IsStringDouble(b)))
	{
		eps = 0.000000005 * StringToDouble(a);
		if (StringToDouble(a) > StringToDouble(b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else
	{
		if (IsStringGt(a,b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	return(s);
}

string LT ( string a, string b )
/* mengecek apakah a lebih kecil dari b, a dan b bisa berupa string, integer dan real 
catatan : pembandingan string dilakukan dengan alfabetis
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error'  */
{
	string s;
	double eps;
	
	if ((IsStringInteger(a)) && (IsStringInteger(b)))
	{
		if (StringToInt(a) < StringToInt(b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else if ((IsStringDouble(a)) && (IsStringDouble(b)))
	{
		eps = 0.000000005 * StringToDouble(a);
		if (StringToDouble(a) < StringToDouble(b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	else
	{
		if (IsStringLt(a,b))
		{
			s = BoolToString(true);
		}
		else
		{
			s = BoolToString(false);
		}
	}
	return(s);
}

string GTOEQ ( string a, string b )
/* mengecek apakah a lebih besar samadengan b, a dan b bisa berupa string, integer dan real 
catatan : pembandingan string dilakukan dengan alfabetis
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error'  */
{
	string s;
	if ((StringToBool(GT(a,b))) || (StringToBool(EQ(a,b))))
	{
		s = BoolToString(true);
	}
	else
	{
		s = BoolToString(false);
	}
	return(s);
}

string LTOEQ ( string a, string b )
/* mengecek apakah a lebih kecil samadengan b, a dan b bisa berupa string, integer dan real 
catatan : pembandingan string dilakukan dengan alfabetis
catatan : pembandingan string dengan tipe integer dan real tidak dimungkinkan
kembalikan string 'error'  */
{
	string s;
	if ((StringToBool(LT(a,b))) || (StringToBool(EQ(a,b))))
	{
		s = BoolToString(true);
	}
	else
	{
		s = BoolToString(false);
	}
	return(s);
}

//-----------------------
//   Operasi Boolean
//-----------------------

string AND ( string a, string b)
/* mengembalikan hasil operasi a AND b jika a dan b adalah boolean
,jika tidak kembalikan string 'error' */
{
	string s;
	
	if (IsStringBoolean(a) && IsStringBoolean(b))
	{
		return (BoolToString(StringToBool(a) && StringToBool(b)));
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string OR ( string a, string b)
/* mengembalikan hasil operasi a OR b jika a dan b adalah boolean
,jika tidak kembalikan string 'error' */
{
	string s;
	
	if (IsStringBoolean(a) && IsStringBoolean(b))
	{
		return (BoolToString(StringToBool(a) || StringToBool(b)));
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string NOT ( string a )
/* mengembalikan hasil negasi dari a jika a adalah boolean
,jika tidak kembalikan string 'error' */
{
	string s;
	
	if (IsStringBoolean(a))
	{
		return (BoolToString(!StringToBool(a)));
	}
	else
	{
		s.s[0] = 'E';
		s.s[1] = 'R';
		s.s[2] = 'R';
		s.s[3] = 'O';
		s.s[4] = 'R';
		s.s[5] = '\0';
		s.length = 5;
	}
	return(s);
}

string IFCOND (string cond, string iftrue, string iffalse)
/* Menghasilkan ifftrue jika cond bernilai true dan iffalse jika cond bernilai false */
/* Menghasilkan error jika cond tidak bernilai boolean */
{
	string s;
	if (IsStringBoolean(cond))
	{
		if (StringToBool(cond))
		{
			return (iftrue);
		}
		else if (!StringToBool(cond))
		{
			return (iffalse);
		}
	}
	else
	{
		s=CharToString("ERROR");
		return(s);
	}
}

//-----------------------
//   Operasi String
//-----------------------

string CONCAT ( string a, string b )
/* menghasilkan konkatenasi dari string a dan b 
catatan : tinggal pake fungsi concat yang di custom_string.h */
{
	return(StrCat(a,b));
}

//-----------------------
//   Operasi terhadap AREA 
//-----------------------
/* Area dinyatakan dalam 2 string, yaitu PosStart dan PosEnd
contoh format Posisi : A12*/

string SUM ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan jumlah semua nilai numerik dari PosStart [pojok kiri atas] sampai 
PosEnd [pojok kanan bawah] 
catatan : jika terdapat nilai non-numerik / error , abaikan
*/
{
	string s, ColAk, ColAw, Pos,temp;
	int i, RowAw, RowAk, tempint;
	double Sums, tempdouble;
	address P;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	Sums = 0;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				if (InfoType(P) == 1)
				{
					tempint = StringToInt(InfoChar(P));
					Sums = Sums + tempint;
				}
				else if (InfoType(P) == 2)
				{
					tempdouble = StringToDouble(InfoChar(P));
					Sums = Sums + tempdouble;
				}
				else if (InfoType(P) == 5){
					GetXYChar(S,Pos,&temp);
					temp=eval(temp ,S);
					if (IsStringInteger(temp)) {
						tempint = StringToInt(temp);
						Sums = Sums + tempint;
						} 
					else if (IsStringDouble(temp)) {
						tempdouble = StringToDouble(temp);
						Sums = Sums + tempdouble;
						}
				}
			}
			NextAlfa(&s);
		}
	}
	if ((Sums-(int)Sums)!=0)
		{s = DoubleToString(Sums);}
	else 
		{s = IntToString((int) Sums);}
	return(s);
}

string AVERAGE ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan nilai rata-rata dari semua nilai numerik [real&integer] dari PosStart [pojok kiri atas] sampai 
PosEnd [pojok kanan bawah] 
catatan : jika terdapat nilai non-numerik / error, abaikan
*/
{
	string s, ColAk, ColAw, Pos, temp;
	int i, RowAw, RowAk, tempint;
	double Sums, tempdouble;
	int Count;
	address P;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	
	Count = 0;
	Sums = 0;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				if (InfoType(P) == 1)
				{
					tempint = StringToInt(InfoChar(P));
					Sums = Sums + tempint;
					Count++;
					
				}
				else if (InfoType(P) == 2)
				{
					tempdouble = StringToDouble(InfoChar(P));
					Sums = Sums + tempdouble;
					Count++;
				}
				else if (InfoType(P) == 5){
					GetXYChar(S,Pos,&temp);
					temp=eval(temp ,S);
					//printf("hasil eval = %s\n",temp.s);
					if (IsStringInteger(temp)) {
						//printf("masuk sini yak");
						tempint = StringToInt(temp);
						Sums = Sums + tempint;
						Count++;
						} 
					else if (IsStringDouble(temp)) {
						//printf("gak masuk sini yak");
						tempdouble = StringToDouble(temp);
						Sums = Sums + tempdouble;
						Count++;
						}
				}
			}
			NextAlfa(&s);
		}
	}
	
	if (Count != 0)
	{
		s = DoubleToString ( Sums / Count );
		return (s);
	}
	else
	{
		s = DoubleToString (0);
		return (s);
	}
}

string COUNTNUM ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan banyak elemen (bertipe numerik [real&integer]) dari PosStart [pojok kiri atas] 
sampai PosEnd [pojok kanan bawah]
catatan : jika terdapat nilai non-numerik / error , abaikan
*/
{
	string s, ColAk, ColAw, Pos;
	int i, RowAw, RowAk;
	int Count;
	address P;
	
	RowAw = 0;
	RowAk = 0;
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	Count = 0;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			
			GetXY(S,Pos,&P);
			
			if (P != Nil)
			{
				if ((InfoType(P) == 1) || (InfoType(P) == 2))
				{
					Count++;
				}
			}
			NextAlfa(&s);
		}
	}
	s = IntToString (Count);
	return(s);
}

string COUNT ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan banyak elemen (bertipe apa pun kecuali error) dari PosStart [pojok kiri atas] 
sampai PosEnd [pojok kanan bawah]*/
{
	string s, ColAk, ColAw, Pos;
	int i, RowAw, RowAk;
	int Count;
	address P;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	Count = 0;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				Count++;
			}
			NextAlfa(&s);
		}
	}
	s = IntToString(Count);
	return(s);
}

string MAXS ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan nilai maksimum dari semua nilai numerik dari PosStart [pojok kiri atas] sampai 
PosEnd [pojok kanan bawah] 
catatan : jika terdapat nilai non-numerik / error etc, abaikan
*/
{
	string s, ColAk, ColAw, Pos;
	int i, RowAw, RowAk, tempint;
	double Max, tempdouble;
	address P;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	Max = 0;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				if (InfoType(P) == 1)
				{
					tempint = StringToInt(InfoChar(P));
					if (tempint > Max)
					{
						Max = tempint;
					}
				}
				else if (InfoType(P) == 2)
				{
					tempdouble = StringToDouble(InfoChar(P));
					if (tempdouble > Max)
					{
						Max = tempdouble;
					}
				}
			}
			NextAlfa(&s);
		}
	}
	s = DoubleToString(Max);
	return(s);
}

string MINI ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan nilai minimum dari semua nilai numerik dari PosStart [pojok kiri atas] sampai 
PosEnd [pojok kanan bawah] 
catatan : jika terdapat nilai non-numerik / error etc, abaikan
*/
{
	string s, ColAk, ColAw, Pos;
	int i, RowAw, RowAk, tempint;
	double Min, tempdouble;
	address P;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	Min = 999999999;
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				if (InfoType(P) == 1)
				{
					tempint = StringToInt(InfoChar(P));
					if (tempint < Min)
					{
						Min = tempint;
					}
				}
				else if (InfoType(P) == 2)
				{
					tempdouble = StringToDouble(InfoChar(P));
					if (tempdouble < Min)
					{
						Min = tempdouble;
					}
				}
			}
			NextAlfa(&s);
		}
	}
	s = DoubleToString(Min);
	return(s);
}

string STDEV ( Sheet S, string PosStart , string PosEnd )
/* mengembalikan nilai standar deviasi dari semua nilai numerik [real&integer] 
dari PosStart [pojok kiri atas] sampai dengan PosEnd [pojok kanan bawah] 
catatan : jika terdapat nilai non-numerik / error, abaikan
*/
{
	string s, ColAk, ColAw, Pos;
	int i, RowAw, RowAk, tempint;
	double Average;
	address P;
	int Count;
	string Temps;
	double Temp, tempdouble;
	double Deviation;
	
	s = AVERAGE(S,PosStart,PosEnd);
	Temps = COUNTNUM(S,PosStart,PosEnd);
	
	Average = atof(s.s);
	Deviation = 0;
	Count = StringToInt(Temps);
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);
	
	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			GetXY(S,Pos,&P);
			if (P != Nil)
			{
				if (InfoType(P) == 1)
				{
					tempint = StringToInt(InfoChar(P));
					Temp = tempint - Average;
					Deviation = Deviation + (Temp * Temp);
				}
				else if (InfoType(P) == 2)
				{
					tempdouble = StringToDouble(InfoChar(P));
					Temp = tempdouble - Average;
					Deviation = Deviation + (Temp * Temp);
				}
			}
			NextAlfa(&s);
		}
	}
	
	if (Count > 1)
	{
		s = DoubleToString(sqrt (Deviation / (Count - 1)));
		return(s);
	}
	else
	{
		s = DoubleToString(0);
		return(s);
	}
}

string SqrXY (Sheet S, string Pos)
/* Menghasilkan nilai kuadrat dari nilai sebuah cell di sheet dengan posisi (Col,Row) */
{
	address P;
	int tempint, sqrr;
	double sqrd, tempdouble;
	
	GetXY(S,Pos,&P);
	if (P != Nil)
	{
		if (InfoType(P) == 1)
		{
			tempint = StringToInt(InfoChar(P));
			sqrr = tempint * tempint;
			return(IntToString(sqrr));
		}
		else if (InfoType(P) == 2)
		{
			tempdouble = StringToDouble(InfoChar(P));
			sqrd = tempdouble * tempdouble;
			return(DoubleToString(sqrd));
		}
		else
		{
			return(DoubleToString(0));
		}
	}
	else
	{
		return (DoubleToString(0));
	}
}
	

string SqrtXY (Sheet S, string Pos)
/* Menghasilkan akar kuadrat dari nilai sebuah cell di sheet dengan posisi (Col,Row) */
{
	address P;
	int tempint, sqrtr;
	double sqrtd, tempdouble;
	
	GetXY(S,Pos,&P);
	if (P != Nil)
	{
		if (InfoType(P) == 1)
		{
			tempint = StringToInt(InfoChar(P));
			sqrtr = tempint * tempint;
			return(IntToString(sqrtr));
		}
		else if (InfoType(P) == 2)
		{
			tempdouble = StringToDouble(InfoChar(P));
			sqrtd = tempdouble * tempdouble;
			return(DoubleToString(sqrtd));
		}
		else
		{
			return(DoubleToString(0));
		}
	}
	else
	{
		return (DoubleToString(0));
	}
}

void PosToCR(string Pos, string *Col, int *Row)
/* Mengubah string posisi menjadi dalam bentuk kolom dan baris */
{
	string TempR;
	int i,j;
	
	i = 0;
	(*Col).length = 0;
	while (!IsNumber(Pos.s[i]))
	{
		(*Col).s[i] = Pos.s[i];
		(*Col).length++;
		i++;
	}
	(*Col).s[i] = '\0';
	
	j = 0;
	TempR.length = 0;
	while (i < Pos.length)
	{
		TempR.s[j] = Pos.s[i];
		TempR.length++;
		i++; j++;
	}
	TempR.s[j] = '\0';
	(*Row) = StringToInt(TempR);
}

void CRToPos (string Column, int Row, string *Pos)
{
	string TempR;
	
	TempR = IntToString(Row);
	(*Pos) = StrCat(Column,TempR);
}
